﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;

namespace Postnuclear
  {
  /// <summary>
  /// The extension methods for the <see cref="ICollection{T}"/>.
  /// </summary>  
  public static partial class ExtensionMethods
    {
    #region Public

    /// <summary>
    /// Adds several elements to collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="ICollection{T}"/>.</param>
    /// <param name="elements">The elements which will be added to collection.</param>
    [DebuggerHidden]
    public static void Add<T>(
      this ICollection<T> source,
      params T[] elements)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(elements != null);

      Contract.Ensures(Contract.ForAll(elements, source.Contains));

      source.Add(elements as IEnumerable<T>);
      }

    /// <summary>
    /// Adds several elements to collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="ICollection{T}"/>.</param>
    /// <param name="elements">The elements which will be added to collection.</param>
    [DebuggerHidden]
    public static void Add<T>(
      this ICollection<T> source,
      IEnumerable<T> elements)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(elements != null);

      Contract.Ensures(Contract.ForAll(elements, source.Contains));

      elements.ForEach(source.Add);
      }

    /// <summary>
    /// Removes several elements from collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="ICollection{T}"/>.</param>
    /// <param name="elements">The elements which will be removed from collection.</param>
    /// <returns>
    /// <c>true</c> if item was successfully removed from the <see cref="ICollection{T}"/>; otherwise, <c>false</c>.
    /// This method also returns false if item is not found in the original <see cref="ICollection{T}"/>.
    /// </returns>
    [DebuggerHidden]
    public static bool Remove<T>(
      this ICollection<T> source,
      params T[] elements)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(elements != null);
      Contract.Requires<ArgumentNullException>(Contract.ForAll(elements, source.Contains));

      Contract.Ensures(Contract.ForAll(elements, element => !source.Contains(element)));

      return source.Remove(elements as IEnumerable<T>);
      }

    /// <summary>
    /// Removes several elements from collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="ICollection{T}"/>.</param>
    /// <param name="elements">The elements which will be removed from collection.</param>
    /// <returns>
    /// <c>true</c> if item was successfully removed from the <see cref="ICollection{T}"/>; otherwise, <c>false</c>.
    /// This method also returns false if item is not found in the original <see cref="ICollection{T}"/>.
    /// </returns>
    [DebuggerHidden]
    public static bool Remove<T>(
      this ICollection<T> source,
      IEnumerable<T> elements)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(elements != null);
      Contract.Requires<ArgumentNullException>(Contract.ForAll(elements, source.Contains));

      Contract.Ensures(Contract.ForAll(elements, element => !source.Contains(element)));

      return elements.All(source.Remove);
      }

    #endregion
    }
  }